# -*- coding: utf-8 -*-
import configparser
import ssl
import time
import traceback

import paho.mqtt.client as mqtt

from conn.MyLogs import MyLogs as pub_logger

f = r'setting.ini'
config = configparser.RawConfigParser()
config.read(f, encoding='UTF8')

use_tsl = False


class Publisher(object):
    def __init__(self, config):
        self.cfg = config
        # publisher配置部分
        self.publisher_cfg = self.cfg["publisher"]
        # mqtt broker配置部分
        self.mqtt_broker_cfg = self.cfg["mqtt_broker"]
        self.client = mqtt.Client()
        # 绑定回调函数
        # 断开连接时候的回调函数
        self.client.on_disconnect = self.disconnect_callback
        self.client.on_publish = self.on_publish_callback
        self.client.on_connect = self.connect_callback
        self.conn_flag = False

    def create_context(self):
        """
        客户端登录信息的设置
        :return:
        """
        context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
        context.load_cert_chain(
            certfile=self.publisher_cfg["certfile"],
            keyfile=self.publisher_cfg["keyfile"],
            password=self.publisher_cfg["cert_pass"],
        )
        return context

    @staticmethod
    def connect_callback(client, userdata, flags, rc):
        assert rc == 0
        global conn_flag
        conn_flag = True
        pub_logger.info("\nMQTT broker connected successfully,\n"
                        "address: {},\n"
                        "   port: {}\n".format(client._host, client._port))

    @staticmethod
    def disconnect_callback(client, userdata, rc):
        # rc == 0, 代表断开连接成功
        assert rc == 0
        pub_logger.info("\nDisconnect from MQTT broker,\n"
                        "address: {},\n"
                        "   port: {}\n".format(client._host, client._port))

    @staticmethod
    def on_publish_callback(client, userdata, mid):
        topic, msg = userdata
        pub_logger.info("\nSuccessfully published message,\n"
                        "[topic]: {}\n"
                        "[content]: {}\n".format(topic, msg))

    def connect_mqtt_broker(self):
        """
        链接mqtt_broker服务器
        :return:
        """
        # 验证
        self.client.username_pw_set(self.mqtt_broker_cfg["username"], self.mqtt_broker_cfg["password"])
        if (use_tsl):
            # 使用context写法
            context = self.create_context()
            self.client.tls_set_context(context)
            # 不用context的写法
            # self.client.tls_set(ca_certs="cert/ca.crt", tls_version=ssl.PROTOCOL_TLSv1_2)
        self.client.tls_insecure_set(use_tsl);
        # 连接 IP port keepalive
        self.client.connect(self.mqtt_broker_cfg["address"],
                            self.mqtt_broker_cfg["port"],
                            self.mqtt_broker_cfg["keepalive"])
        while not conn_flag:
            time.sleep(0.1)
            self.client.loop()

    def disconnect_mqtt_broker(self):
        self.client.disconnect()

    def publish_msg(self, topic, msg):
        """
        发送一条消息
        :param topic:
        :param msg:
        :return:
        """
        pub_logger.info("\nPublishing message,\n"
                        "[topic]: {}\n"
                        "[content]: {}\n".format(topic, msg))
        self.client.user_data_set((topic, msg))
        # 发布 topic 内容
        self.client.publish(topic, payload=msg.encode(), qos=0)


def demo():
    message = "congratulation, this is a mqtt message."
    try:
        publisher = Publisher(cfg=config)
        publisher.connect_mqtt_broker()
        publisher.publish_msg(topic=config["publisher"]["topic"], msg=message)
        publisher.disconnect_mqtt_broker()

    except Exception as e:
        # 服务启动失败
        pub_logger.error(traceback.format_exc())
        raise e


if __name__ == '__main__':
    demo()
